package com.chenu.gamscriptman.config;

import com.chenu.gamscriptman.compoent.ChenuMD5PasswordEncoder;
import com.chenu.gamscriptman.compoent.Global;
import com.chenu.gamscriptman.domain.User;
import com.chenu.gamscriptman.service.UserService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

/**
 * @author flyan
 * date 2019-12-24
 * @function
 */
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private Logger logger = LoggerFactory.getLogger(this.getClass());


    @Autowired
    private HttpSession session;

    @Autowired
    private ChenuMD5PasswordEncoder chenuMD5PasswordEncoder;

    /* 用户服务 */
    @Autowired
    private UserService userService;

    /**
     * 配置 http请求 授权规则
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 定制请求的授权规则
        http.authorizeRequests()
                .antMatchers("/usr/login").permitAll()                  /* 登录页面任何人都可以访问 */
                .antMatchers("/error").permitAll()                      /* 不拦截错误页面 */
                // 不拦截资源
                .antMatchers("/asserts/**", "/resources/**", "/webjars/**").permitAll()
                // 不拦截测试页面 和 自定义错误页面
                .antMatchers("/test**", "/error").permitAll()
                /* 最重要的，系统API不要拦截，它们通过别的方式请求验证 */
                .antMatchers(
                        "/device/save_or_update",       /* 保存或更新一条设备信息 */
                        "/device/get",                              /* 获取一条设备信息 */
                        "/userdata/get",                            /* 获取一条用户数据 */
                        "/userdata/save_or_update",                 /* 保存或更新一条用户数据 */
                        "/gamedata/get",                            /* 获取一个设备的游戏数据 */
                        "/doc/get"                                  /* 获取文档内容 */
                ).permitAll()
                /* 登录用户才可进入后台页面 */
                .antMatchers("/**", "/index/**").hasRole("USER");

        /* 设置csrf校验，忽略我们的API接口调用，它们是给设备调用的，没法完成csrf校验 */
        http.csrf().ignoringAntMatchers(
                "/device/save_or_update",       /* 保存或更新一条设备信息 */
                "/device/get",                  /* 获取一条设备信息 */
                "/userdata/get",                /* 获取一条用户数据 */
                "/userdata/save_or_update",     /* 保存或更新一条用户数据 */
                "/gamedata/get",                /* 获取一个设备的游戏数据 */
                "/doc/get"                      /* 获取文档内容 */
        );

        // 开启自动配置的登录功能
        http.formLogin().loginPage("/usr/login")
                /* 登录成功默认跳转 */
                .defaultSuccessUrl("/")
                // 配置登录成功处理例程
                .successHandler(new SavedRequestAwareAuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        // 将登录成功的用户放入seession中
                        Object obj = authentication.getPrincipal();
                        if(obj instanceof User){    /* 说明是数据库中的用户 */
                            User user = (User) obj;
                            session.setAttribute(Global.SESSION_LOGIN_U_UID, user.getUid());
                            session.setAttribute(Global.SESSION_LOGIN_U_UNAME, user.getUsername());
                            session.setAttribute(Global.SESSION_LOGIN_U_ROLE, user.getRole());
                            session.setAttribute(Global.SESSION_LOGIN_U_NICKNAME, user.getUinfo().getNickname());
                            logger.info("当前登录用户 --> " + user.toString());
                        } else {
                            // 说明是固有的root用户
                            UserDetails userDetails = (UserDetails)obj;
                            session.setAttribute(Global.SESSION_LOGIN_U_UID, 0);
                            session.setAttribute(Global.SESSION_LOGIN_U_UNAME, userDetails.getUsername());
                            session.setAttribute(Global.SESSION_LOGIN_U_ROLE, User.ROOT);
                            logger.info("当前登录用户 --> " + userDetails.toString());
                        }
                        //处理完成后，跳转回原请求URL
                        super.onAuthenticationSuccess(request, response, authentication);
                    }
                })
                /* 配置登录失败处理 */
                .failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
                        /* 设置全局错误信息 */
                        session.setAttribute(Global.SESSION_ERR_MESSAGE, "用户名和密码不匹配，请重试！");
                        /* 还是回到登录页面，因为没登录成功，重定向到哪都得去登录页面 */
                        response.sendRedirect("/");
                    }
                });

        // 开启自动配置的注销功能，注销成功后来到首页
        http.logout().logoutSuccessUrl("/");

        // 开启记住我功能
        http.rememberMe().rememberMeParameter("remember");

    }

    /**
     * 定制认证规则
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("chenu").password("flyan@chenu").roles("ROOT", "USER");   /* 系统固有root用户 */
        // 设置用户从数据库中获取，并使用MD5加密
        auth.userDetailsService(userService).passwordEncoder(chenuMD5PasswordEncoder);
    }

}
